#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>

using namespace std;

const int N = 1010;
int f[N];
int n, k = 1;
struct Node {
    int x, y, h;
} node[N];

// 千万要注意边的条数啊，边最大是有n * (n - 1) / 2 条
struct Edge {
    int from, to;
    double cost;
} edge[N * N];


int Find(int x) {
    return f[x] = f[x] == x ? x : Find(f[x]);
}

void Union(int x, int y) {
    f[y] = f[x];
}

double kruskal() {
    double sum = 0;
    sort(edge, edge + k, [](const Edge& x, const Edge& y) {
        return x.cost < y.cost;
    });

    for (int i = 1; i <= n; ++i) {
        f[i] = i;
    }

    int e = 0;
    for (int i = 1; i <= k - 1 && e < n - 1; ++i) {
        if (Find(edge[i].from) != Find(edge[i].to)) {
            sum += edge[i].cost;
            // 这个地方注意合并的时候是要合并两个集合，你首先要找到它们的领队然后传进去
            Union(Find(edge[i].from), Find(edge[i].to));
            e++;
        }
    }
    return sum;
}

int main() {

    cin >> n;

    for (int i = 1; i <= n; ++i) {
        cin >> node[i].x >> node[i].y >> node[i].h;
    }

    for (int i = 1; i <= n; ++i) {
        for (int j = i + 1; j <= n; ++j) {
            edge[k].from = i;
            edge[k].to = j;
            edge[k++].cost = sqrt(pow(node[i].x - node[j].x, 2) + pow(node[i].y - node[j].y, 2)) + pow(node[i].h - node[j].h ,2);
        }
    }

    double res = kruskal();
    cout << fixed << setprecision(2) << res << endl;
    return 0;
}